# -*- coding: utf-8 -*-
# @Author: 16601513301
# @Date:   2025-09-24 16:56:28
# @Last Modified by:   18860233105
# @Last Modified time: 2025-09-24 18:42:03
# 获取cookie
from setting import *
from weibo_login_cookie import *
from weibo_user_info import *
import myglobal
import random
import json
import time
import requests
from datetime import datetime, timedelta
from collections import defaultdict, deque
import pickle
import os
import threading

# 全局变量
_current_valid_type = None
_cookie_cache = {}
_cache_expiry = {}
_cache_duration = 300  # 缓存持续时间（秒）

# 成功率统计
_success_stats = defaultdict(lambda: {'success': 0, 'total': 0})
_stats_lock = threading.Lock()
_stats_history = deque(maxlen=100)

# 重试策略配置
_retry_config = {
    'max_retries': 3,
    'base_delay': 1,
    'max_delay': 10,
    'backoff_factor': 2,
    'success_threshold': 0.8,
}

# 验证配置 - 使用更简单的验证接口
_validation_config = {
    'timeout': 10,
    'test_url': 'https://weibo.com/ajax/statuses/hot_band',  # 微博热搜接口，不需要特定用户权限
    'required_fields': ['SUB', 'SUBP', 'XSRF-TOKEN'],
    'min_cookie_count': 3,
}

# 统计文件路径
_STATS_FILE = 'cookie_stats.pkl'

def getweiboCookie():
    try:
        with open(COOKIE_PATH, mode="r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        print(f"读取COOKIE_PATH文件失败: {e}")
        return ""

def getweiboCookie2():
    try:
        with open(COOKIE_PATH2, mode="r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        print(f"读取COOKIE_PATH2文件失败: {e}")
        return ""

def validate_cookie_detailed(cookies):
    """
    详细的Cookie验证逻辑
    """
    try:
        # 1. 基本检查
        if not cookies or not isinstance(cookies, dict):
            return False, "Cookie为空或不是字典格式"
        
        if len(cookies) < _validation_config['min_cookie_count']:
            return False, f"Cookie数量不足，至少需要{_validation_config['min_cookie_count']}个"
        
        # 2. 必要字段检查
        missing_fields = []
        for field in _validation_config['required_fields']:
            if field not in cookies:
                missing_fields.append(field)
        
        if missing_fields:
            return False, f"缺少必要字段: {missing_fields}"
        
        # 3. 字段值检查
        for key, value in cookies.items():
            if not value or str(value).strip() == "":
                return False, f"字段 {key} 的值为空"
            if len(str(value)) < 2:
                return False, f"字段 {key} 的值过短"
        
        # 4. 网络验证（使用更简单的接口）
        is_valid, message = validate_cookie_online_safe(cookies)
        if not is_valid:
            return False, message
        
        # 5. 过期时间检查
        if 'ALF' in cookies:
            try:
                alf_timestamp = int(cookies['ALF'])
                if alf_timestamp < time.time():
                    return False, "Cookie已过期（ALF时间戳检查）"
            except ValueError:
                pass
        
        return True, "Cookie验证通过"
        
    except Exception as e:
        return False, f"验证过程中发生错误: {e}"

def validate_cookie_online_safe(cookies):
    """
    安全的在线验证Cookie有效性 - 使用不需要特定权限的接口
    """
    try:
        # 避免频繁验证
        if not hasattr(validate_cookie_online_safe, 'last_validate_time'):
            validate_cookie_online_safe.last_validate_time = 0
        
        current_time = time.time()
        if current_time - validate_cookie_online_safe.last_validate_time < 60:
            return True, "跳过在线验证"
        
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json, text/plain, */*',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': 'https://weibo.com/'
        }
        
        session = requests.Session()
        for key, value in cookies.items():
            session.cookies.set(key, value)
        
        response = session.get(
            _validation_config['test_url'],
            headers=headers,
            timeout=_validation_config['timeout']
        )
        
        validate_cookie_online_safe.last_validate_time = current_time
        
        if response.status_code == 200:
            try:
                data = response.json()
                # 检查是否触发验证码
                if data.get('ok') == -100 or data.get('errno') == '-100':
                    return False, "触发验证码，需要人工验证"
                
                # 热搜接口成功返回数据
                if isinstance(data, dict) and ('data' in data or 'ok' in data):
                    return True, "在线验证成功"
                else:
                    return False, "接口返回数据格式异常"
            except json.JSONDecodeError:
                # 如果不是JSON格式但状态码为200，也认为是成功的
                return True, "响应非JSON格式但状态码为200"
        elif response.status_code == 403:
            return False, "访问被拒绝（403错误）"
        elif response.status_code == 404:
            return False, "接口不存在（404错误）"
        else:
            return False, f"接口请求失败，状态码: {response.status_code}"
            
    except requests.exceptions.Timeout:
        return False, "在线验证请求超时"
    except requests.exceptions.RequestException as e:
        return False, f"在线验证网络错误: {e}"
    except Exception as e:
        return False, f"在线验证异常: {e}"

def validate_cookie_basic(cookies):
    """
    基础验证 - 只检查必要字段，不进行网络验证
    """
    try:
        if not cookies or not isinstance(cookies, dict):
            return False, "Cookie为空或不是字典格式"
        
        if len(cookies) < _validation_config['min_cookie_count']:
            return False, f"Cookie数量不足"
        
        missing_fields = []
        for field in _validation_config['required_fields']:
            if field not in cookies:
                missing_fields.append(field)
        
        if missing_fields:
            return False, f"缺少必要字段: {missing_fields}"
        
        # 检查关键字段的值
        for key in _validation_config['required_fields']:
            if key in cookies and (not cookies[key] or len(str(cookies[key])) < 2):
                return False, f"字段 {key} 的值无效"
        
        return True, "基础验证通过"
    except Exception as e:
        return False, f"基础验证错误: {e}"

def update_success_stats(type_num, success):
    """更新成功率统计"""
    with _stats_lock:
        _success_stats[type_num]['total'] += 1
        if success:
            _success_stats[type_num]['success'] += 1
        
        _stats_history.append({
            'timestamp': datetime.now(),
            'type': type_num,
            'success': success
        })

def get_success_rate(type_num):
    """获取指定type的成功率"""
    stats = _success_stats[type_num]
    if stats['total'] == 0:
        return 0.0
    return stats['success'] / stats['total']

def get_best_type():
    """获取成功率最高的type"""
    if not _success_stats:
        return random.randint(1, 5)
    
    # 过滤掉成功率太低的type
    valid_types = [t for t in _success_stats.keys() if get_success_rate(t) > 0.1]
    if not valid_types:
        return random.randint(1, 5)
    
    best_type = max(valid_types, key=lambda x: get_success_rate(x))
    
    if get_success_rate(best_type) >= _retry_config['success_threshold']:
        return best_type
    else:
        return random.randint(1, 5)

def save_stats():
    """保存统计信息到文件"""
    try:
        stats_data = {
            'success_stats': dict(_success_stats),
            'stats_history': list(_stats_history),
            'saved_time': datetime.now()
        }
        with open(_STATS_FILE, 'wb') as f:
            pickle.dump(stats_data, f)
    except Exception as e:
        print(f"保存统计信息失败: {e}")

def load_stats():
    """从文件加载统计信息"""
    global _success_stats, _stats_history
    try:
        if os.path.exists(_STATS_FILE):
            with open(_STATS_FILE, 'rb') as f:
                stats_data = pickle.load(f)
                _success_stats.update(stats_data.get('success_stats', {}))
                # 只保留最近记录
                new_history = stats_data.get('stats_history', [])[-100:]
                _stats_history.extend(new_history)
    except Exception as e:
        print(f"加载统计信息失败: {e}")

def get_cached_cookie(type_num):
    """从缓存获取Cookie"""
    current_time = time.time()
    if (type_num in _cookie_cache and 
        type_num in _cache_expiry and 
        current_time < _cache_expiry[type_num]):
        return _cookie_cache[type_num]
    return None

def set_cached_cookie(type_num, cookies):
    """设置Cookie缓存"""
    current_time = time.time()
    _cookie_cache[type_num] = cookies
    _cache_expiry[type_num] = current_time + _cache_duration

def clear_expired_cache():
    """清理过期缓存"""
    current_time = time.time()
    expired_types = [t for t, expiry in _cache_expiry.items() if current_time >= expiry]
    
    for type_num in expired_types:
        _cookie_cache.pop(type_num, None)
        _cache_expiry.pop(type_num, None)

def calculate_retry_delay(attempt):
    """计算重试延迟时间"""
    delay = _retry_config['base_delay'] * (_retry_config['backoff_factor'] ** attempt)
    return min(delay, _retry_config['max_delay'])

def get_next_type_with_strategy(current_type):
    """根据策略获取下一个要尝试的type"""
    # 收集所有type的成功率
    success_rates = {}
    for type_num in range(1, 6):
        success_rates[type_num] = get_success_rate(type_num)
    
    # 按成功率排序，跳过当前type
    sorted_types = sorted([t for t in success_rates.keys() if t != current_type], 
                         key=lambda x: success_rates[x], reverse=True)
    
    if sorted_types:
        return sorted_types[0]
    return (current_type % 5) + 1

def get_cookie(type=None, use_online_validation=True):
    """
    获取微博Cookie，支持失败重试机制和缓存
    
    Args:
        type: 指定获取方式
        use_online_validation: 是否使用在线验证（遇到验证码时可设为False）
    """
    global _current_valid_type
    
    if not _success_stats:
        load_stats()
    
    clear_expired_cache()
    
    # 确定要使用的type
    if type is None:
        if _current_valid_type and get_success_rate(_current_valid_type) >= 0.3:
            type = _current_valid_type
            print(f"使用之前有效的type: {type} (成功率: {get_success_rate(type):.2f})")
        else:
            type = get_best_type()
            print(f"使用最佳type: {type} (成功率: {get_success_rate(type):.2f})")
    
    max_retries = _retry_config['max_retries']
    attempted_types = set()
    
    for attempt in range(max_retries):
        # 检查缓存
        cached_cookie = get_cached_cookie(type)
        if cached_cookie:
            print(f"✅ 从缓存获取type {type}的Cookie")
            update_success_stats(type, True)
            return cached_cookie
        
        attempted_types.add(type)
        
        try:
            cookies = {}
            
            if type == 1:
                cookie_str = getweiboCookie()
                cookies = json.loads(cookie_str) if cookie_str else {}
                    
            elif type == 2:
                target_cookies = get_specific_cookies()
                print(f"✅ cookie已保存到文件")
                cookie_str = getweiboCookie2()
                cookies = json.loads(cookie_str) if cookie_str else {}
                    
            elif type == 3:
                user_id = myglobal.user_id
                cookies = get_weibo_rand_cookie(user_id=user_id)
                
            elif type == 4:
                cookies = {
                    '_T_WM': "91527798931", 'ALF': "1761291802",
                    'M_WEIBOCN_PARAMS': "uicode=20000174", 'MLOGIN': "1",
                    'mweibo_short_token': "a7ab137f28",
                    'SCF': "AsruMd9nHNgofQjdMUQgnQ1AKoIEeQgIkAnA2A8gbw3Ygzps2ynSGWb1_Ng5H8-qpH6d4XezBnUIkHthNYxvRjw.",
                    'SUB': "_2A25F19FKDeRhGeFG7VQS-SbOzzuIHXVmrWyCrDV6PUJbktANLWPTkW1NeQJaMX1CNfnL4iLR8J3MIsjazsLKQXwx",
                    'SUBP': "0033WrSXqPxfM725Ws9jqgMF55529P9D9WWoridYzWcD1oFrYREC-0yO5JpX5KMhUgL.FoMRSoq01KnEShM2dJLoIp7LxK.L1KMLBo.LxK.L1KMLBo._i--Xi-iFi-iF",
                    'WEIBOCN_FROM': "1110006030", 'XSRF-TOKEN': "9574fe",
                }
            elif type == 5:
                target_cookies = get_specific_cookies()
                print(f"✅ cookie已保存到文件")
                cookie_str = getweiboCookie2()
                cookies = json.loads(cookie_str) if cookie_str else {}
            else:
                print(f"无效的type: {type}")
                type = get_next_type_with_strategy(type)
                continue
            
            # 根据参数选择验证方式
            if use_online_validation:
                is_valid, message = validate_cookie_detailed(cookies)
            else:
                is_valid, message = validate_cookie_basic(cookies)
            
            if is_valid:
                _current_valid_type = type
                set_cached_cookie(type, cookies)
                update_success_stats(type, True)
                print(f"✅ type {type} 获取Cookie成功: {message}")
                return cookies
            else:
                print(f"❌ type {type} Cookie验证失败: {message}")
                update_success_stats(type, False)
                
                delay = calculate_retry_delay(attempt)
                print(f"等待 {delay} 秒后重试...")
                time.sleep(delay)
                
                type = get_next_type_with_strategy(type)
                while type in attempted_types and len(attempted_types) < 5:
                    type = get_next_type_with_strategy(type)
                    
        except Exception as e:
            print(f"❌ type {type} 获取Cookie时发生错误: {e}")
            update_success_stats(type, False)
            
            delay = calculate_retry_delay(attempt)
            time.sleep(delay)
            
            type = get_next_type_with_strategy(type)
            while type in attempted_types and len(attempted_types) < 5:
                type = get_next_type_with_strategy(type)
    
    print("❌ 所有获取方式都失败")
    save_stats()
    return {}

def rand_cookie(use_online_validation=True):
    """随机获取Cookie"""
    return get_cookie(type=None, use_online_validation=use_online_validation)

def print_stats():
    """打印统计信息"""
    print("\n=== Cookie获取统计 ===")
    for type_num in sorted(_success_stats.keys()):
        stats = _success_stats[type_num]
        success_rate = get_success_rate(type_num)
        print(f"Type {type_num}: 成功 {stats['success']}/{stats['total']} (成功率: {success_rate:.2%})")
    
    if _current_valid_type:
        print(f"当前有效类型: {_current_valid_type}")

def reset_stats():
    """重置统计信息"""
    global _success_stats, _stats_history
    _success_stats.clear()
    _stats_history.clear()
    if os.path.exists(_STATS_FILE):
        os.remove(_STATS_FILE)
    print("统计信息已重置")

# 初始化
load_stats()

if __name__ == "__main__":
    # 测试 - 使用基础验证避免触发验证码
    print("=== 测试Cookie获取（基础验证）===")
    cookie = rand_cookie(use_online_validation=False)
    
    if cookie:
        print(f"✅ 获取成功，共{len(cookie)}个Cookie")
        # 显示前几个键
        keys = list(cookie.keys())[:5]
        print(f"Cookie键示例: {keys}")
    else:
        print("❌ 获取失败")
    
    print_stats()
    save_stats()
